package com.smart.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.smart.common.PageInfo;
import com.smart.common.domain.BaseEntity;
import com.smart.common.enums.ErrorCode;
import com.smart.common.utils.AssertUtil;
import com.smart.mapper.OperatePermissionMapper;
import com.smart.mapper.OperateRolePermissionMapper;
import com.smart.model.convert.OperatePermissionConvert;
import com.smart.model.domain.OperatePermissionDO;
import com.smart.model.domain.OperateRolePermissionDO;
import com.smart.model.dtomapper.OperateRoleDtoMapper;
import com.smart.model.domain.OperateRoleDO;
import com.smart.mapper.OperateRoleMapper;
import com.smart.model.request.OperateRoleRequest;
import com.smart.model.request.RoleAddRequest;
import com.smart.model.request.RoleUpdateRequest;
import com.smart.model.vo.OperatePermissionVO;
import com.smart.service.OperateRoleService;
import com.smart.model.convert.OperateRoleConvert;
import com.smart.model.vo.OperateRoleVO;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @author zhanghong
 */
@Service
public class OperateRoleServiceImpl extends ServiceImpl<OperateRoleMapper, OperateRoleDO> implements OperateRoleService {
    @Autowired
    private OperateRoleMapper operateRoleMapper;
    @Autowired
    private OperatePermissionMapper operatePermissionMapper;
    @Autowired
    private OperateRolePermissionMapper operateRolePermissionMapper;

    @Override
    public OperateRoleVO getByKey(long id) {
        OperateRoleDO operateRoleDO = getById(id);
        OperateRoleVO operateRoleVO = OperateRoleDtoMapper.INSTANCE.do2VO(operateRoleDO);
        List<OperatePermissionDO> permissionDOS = operatePermissionMapper.findByRoleId(operateRoleVO.getId());
        if (CollectionUtils.isNotEmpty(permissionDOS)) {
            List<OperatePermissionVO> permissionVOS = OperatePermissionConvert.buildOperatePermissionVoList(permissionDOS);
            operateRoleVO.setPermissions(permissionVOS);
        }
        return operateRoleVO;
    }

    @Override
    public PageInfo<OperateRoleVO> pageQuery(OperateRoleRequest request) {
        long count = operateRoleMapper.pageCount(request);
        List<OperateRoleDO> list = operateRoleMapper.pageQuery(request, request.getPageSize(), request.fetchOffSet());
        List<OperateRoleVO> operateRoleVOList = OperateRoleConvert.buildOperateRoleVoList(list);
        for (OperateRoleVO operateRoleVO : operateRoleVOList) {
            List<OperatePermissionDO> permissionDOS = operatePermissionMapper.findByRoleId(operateRoleVO.getId());
            if (CollectionUtils.isNotEmpty(permissionDOS)) {
                List<OperatePermissionVO> permissionVOS = OperatePermissionConvert.buildOperatePermissionVoList(permissionDOS);
                operateRoleVO.setPermissions(permissionVOS);
            }
        }
        return new PageInfo(request.getPageNum(), request.getPageSize(), operateRoleVOList, count);
    }

    @Override
    public List<OperateRoleVO> listQuery(OperateRoleRequest request) {
        // 排除超级管理员角色id
        List<OperateRoleDO> list = lambdaQuery().ne(BaseEntity::getId, 1).list();
        List<OperateRoleVO> operateRoleVOS = OperateRoleConvert.buildOperateRoleVoList(list);
        for (OperateRoleVO operateRoleVO : operateRoleVOS) {
            List<OperatePermissionDO> permissionDOS = operatePermissionMapper.findByRoleId(operateRoleVO.getId());
            if (CollectionUtils.isNotEmpty(permissionDOS)) {
                List<OperatePermissionVO> permissionVOS = OperatePermissionConvert.buildOperatePermissionVoList(permissionDOS);
                operateRoleVO.setPermissions(permissionVOS);
            }
        }
        return operateRoleVOS;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean add(RoleAddRequest request) {
        AssertUtil.assertNotEmpty(request.getPermissionIds(), "权限菜单不能为空");
        OperateRoleDO role = new OperateRoleDO();
        role.setRoleName(request.getRoleName());
        role.setDescription(request.getDescription());

        OperateRoleDO isExist = operateRoleMapper.findByName(role.getRoleName());
        AssertUtil.assertNull(isExist, ErrorCode.ROLE_IS_EXIST);
        super.save(role);
        List<OperateRolePermissionDO> rolePermissions = new ArrayList<>();
        if(CollectionUtils.isNotEmpty(request.getPermissionIds())) {
            for (Long item : request.getPermissionIds()) {
                OperateRolePermissionDO rolePermission = new OperateRolePermissionDO();
                rolePermission.setRoleId(role.getId());
                rolePermission.setPermissionId(item);
                rolePermissions.add(rolePermission);
            }
            operateRolePermissionMapper.batchDO(rolePermissions);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateByKey(RoleUpdateRequest request) {
        OperateRoleDO role = new OperateRoleDO();
        role.setId(request.getId());
        role.setRoleName(request.getRoleName());
        role.setDescription(request.getDescription());
        OperateRoleDO isExist = operateRoleMapper.findByName(role.getRoleName());
        if (isExist != null && isExist.getId() != request.getId().intValue()) {
            AssertUtil.assertTrue(isExist.getId().equals(role.getId()), ErrorCode.ROLE_IS_EXIST);
        }
        super.saveOrUpdate(role);
        List<OperateRolePermissionDO> rolePermissions = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(request.getPermissionIds())) {
            for (Long item : request.getPermissionIds()) {
                OperateRolePermissionDO rolePermission = new OperateRolePermissionDO();
                rolePermission.setRoleId(role.getId());
                rolePermission.setPermissionId(item);
                rolePermissions.add(rolePermission);
            }
            operateRolePermissionMapper.deleteByRoleId(role.getId());
            rolePermissions = rolePermissions.stream().filter(distinctByKey(OperateRolePermissionDO::getPermissionId)).collect(Collectors.toList());
            operateRolePermissionMapper.batchDO(rolePermissions);
        }
        return true;
    }

    @Override
    public Boolean remove(long roleId) {
        long cnt = operateRoleMapper.countByRoleId(roleId);
        AssertUtil.assertTrue(cnt == 0, ErrorCode.EXIST_BIND_USER_ERR);
        operateRoleMapper.deleteDOById(roleId);
        operateRolePermissionMapper.deleteByRoleId(roleId);
        return true;
    }

    /**
     * 根据指定属性进行去重
     * @param keyExtractor
     * @param <T>
     * @return
     */
    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Set<Object> seen = ConcurrentHashMap.newKeySet();
        return t -> seen.add(keyExtractor.apply(t));
    }
}
